package com.guigu.exam.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.guigu.exam.entity.ExamRecord;
import com.guigu.exam.entity.Paper;
import com.guigu.exam.entity.PaperQuestion;
import com.guigu.exam.exception.ExamException;
import com.guigu.exam.mapper.ExamRecordMapper;
import com.guigu.exam.mapper.PaperMapper;
import com.guigu.exam.mapper.PaperQuestionMapper;
import com.guigu.exam.service.PaperQuestionService;
import com.guigu.exam.service.PaperService;
import com.guigu.exam.vo.PaperVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


/**
 * 试卷服务实现类
 */
@Slf4j
@Service
public class PaperServiceImpl extends ServiceImpl<PaperMapper, Paper> implements PaperService {
    @Autowired
    private PaperQuestionService paperQuestionService;
    @Autowired
    private PaperQuestionMapper paperQuestionMapper;
    @Autowired
    private ExamRecordMapper examRecordMapper;

    /**
     * 根据id查询试卷详情（包含试卷中的题目）
     *
     * @param id
     * @return
     */
    @Override
    public Paper getDetailById(Integer id) {
        //根据id查询试卷详情（包含试卷中的题目）
        Paper paper = baseMapper.getDetailById(id);
        return paper;
    }

    /**
     * 创建试卷
     *
     * @param paperVo
     */
    @Override
    public void createPaper(PaperVo paperVo) {
        //判断创建之后的试卷名是否已经存在
        boolean exists = baseMapper.exists(new LambdaQueryWrapper<Paper>().eq(Paper::getName, paperVo.getName()));
        if (exists) {
            //该试卷名已经存在
            throw new ExamException(1002, "该试卷名已经存在");
        }
        //创建Paper对象
        Paper paper = new Paper();
        //将PaperVo对象中的属性值复制到Paper对象中
        BeanUtils.copyProperties(paperVo, paper);
        //设置当前试卷的状态为草稿
        paper.setStatus("DRAFT");
        //获取当前试卷中所有的题目
        Map<Integer, BigDecimal> questions = paperVo.getQuestions();
        //计算当前试卷的总分
        BigDecimal totalScore = questions.values().stream().reduce(BigDecimal.ZERO, BigDecimal::add);
        //设置试卷的总分
        paper.setTotalScore(totalScore);
        //设置题目的总数量
        //map.size取到的是map中不重复的键值对的个数
        paper.setQuestionCount(questions.size());
        //保存试卷
        baseMapper.insert(paper);
        //将 Map<Integer, BigDecimal> 转换为 List<PaperQuestion>
        /*map.entrySet() 是 Map 接口中一个非常重要的方法，它返回一个 包含所有键值对（Map.Entry 对象）的 Set 视图。*/
        List<PaperQuestion> paperQuestionList = questions.entrySet().stream().map(entry -> {
            //创建PaperQuestion对象
            PaperQuestion paperQuestion = new PaperQuestion(paper.getId(), Long.valueOf(entry.getKey().toString()), entry.getValue());
            return paperQuestion;
        }).collect(Collectors.toList());
        //往中间表中批量插入数据
        paperQuestionService.saveBatch(paperQuestionList);
    }

    /**
     * 更新试卷
     *
     * @param id
     * @param paperVo
     */
    @Override
    public void updatePaper(Integer id, PaperVo paperVo) {
        //根据id查询数据库中的试卷
        Paper paper = baseMapper.selectById(id);
        //判断当前试卷是否是已发布的试卷
        if ("PUBLISHED".equals(paper.getStatus())) {
            //该试卷已经发布，不能修改
            throw new ExamException(1001, "该试卷已经发布，不能修改");
        }
        //判断修改之后的试卷名是否已经存在
        boolean exists = baseMapper.exists(new LambdaQueryWrapper<Paper>().eq(Paper::getName, paperVo.getName()).ne(Paper::getId, id));
        if (exists) {
            //该试卷名已经存在
            throw new ExamException(1002, "该试卷名已经存在");
        }
        //将PaperVo对象中的属性值复制到Paper对象中
        BeanUtils.copyProperties(paperVo, paper);
        //获取当前试卷中所有的题目
        Map<Integer, BigDecimal> questions = paperVo.getQuestions();
        //计算当前试卷的总分
        BigDecimal tatolScore = questions.values().stream().reduce(BigDecimal.ZERO, BigDecimal::add);
        //设置试卷的总分
        paper.setTotalScore(tatolScore);
        //设置题目的总数量
        paper.setQuestionCount(questions.size());
//更新试卷信息
        baseMapper.updateById(paper);
        //先删除中间表中原来的数据
        int delete = paperQuestionMapper.delete(new LambdaQueryWrapper<PaperQuestion>().eq(PaperQuestion::getPaperId, id));
        //往中间表中插入数据
        //将 Map<Integer, BigDecimal> 转换为 List<PaperQuestion>
        List<PaperQuestion> paperQuestionList = questions.entrySet().stream().map(entry -> {

            PaperQuestion paperQuestion = new PaperQuestion(paper.getId(), Long.valueOf(entry.getKey().toString()), entry.getValue());
            return paperQuestion;
        }).collect(Collectors.toList());
        //往中间表中批量插入数据
        paperQuestionService.saveBatch(paperQuestionList);
    }

    /**
     * 更新试卷状态
     *
     * @param id
     * @param status
     */
    @Override
    public void updatePaperStatus(Integer id, String status) {
        //判断该试卷是否有进行中的考试记录
        Long count = examRecordMapper.selectCount(new LambdaQueryWrapper<ExamRecord>().eq(ExamRecord::getExamId, id).eq(ExamRecord::getStatus, "进行中"));
        if (count > 0) {
            //改试卷正在进行考试，不能修改状态
            throw new ExamException(1004, "改试卷正在进行考试，不能修改状态");
        }
        //更新试卷状态
        baseMapper.update(null, new LambdaUpdateWrapper<Paper>().set(Paper::getStatus, status).eq(Paper::getId, id));
    }

    @Override
    public void deletePaperById(Integer id) {
        //判断要删除的试卷是否是已发布的试卷
        Paper paper = baseMapper.selectById(id);
        //判断当前试卷是否是已发布的试卷
        if ("PUBLISHED".equals(paper.getStatus())) {
            //该试卷已经发布，不能修改
            throw new ExamException(1001, "该试卷已经发布，不能修改");
        }
        //判断该试卷是否有对应的考试记录
        Long count = examRecordMapper.selectCount(new LambdaQueryWrapper<ExamRecord>().eq(ExamRecord::getExamId, id));
        if (count > 0) {
            //该试卷有对应的考试记录，不能删除
            throw new ExamException(1003, "该试卷有对应的考试记录，不能删除");
        }
        //删除试卷

        baseMapper.deleteById(id);
        //删除中间表中的数据
        paperQuestionMapper.delete(new LambdaQueryWrapper<PaperQuestion>().eq(PaperQuestion::getPaperId, id));
    }
}